package dev

import (
	"awesome-devops/applications/tools"
	"awesome-devops/helper"
	"gitee.com/jjawesomejj/awesome-util/helper/commonhelper"
)

/*
*
任务执行的流程
*/
type Stream struct {
	Stdout *tools.StdWriterWithPid
	Stderr *tools.StdWriterWithPid
}
type Step interface {
	Run() (output string, err error)
	SetStd(standard *tools.Standard)
	SetTimeOutHandler(fun func() (time int, echoWords string, callBack func()))
}

type StepStream interface {
	Run() (Stream *Stream, err error)
	SetStd(std *tools.Standard)
	SetTimeOutHandler(fun func() (time int, echoWords string, callBack func()))
}

type BasicBuildStep struct {
	//构建参数
	args map[string]interface{}
	//工作的路径
	WorkPath string
	//需要执行的shell
	Shell       string
	Std         *tools.Standard
	TimeOutFunc func() (time int, echoWords string, callBack func())
}

func (step *BasicBuildStep) SetStd(standard *tools.Standard) {
	step.Std = standard
}
func (step *BasicBuildStep) SetTimeOutHandler(fun func() (time int, echoWords string, callBack func())) {
	step.TimeOutFunc = fun
}

/*
*
这些命令将在devops的机器上执行
构建shell 比如前端项目可以执行例如npm run build等命令
后端等需要编译的语言可以执行例如go build .等命令
等代码发布了之后那么就可以执行传输命令将数据传输到需要部署的服务器
*/
func (step *BasicBuildStep) Run() (string, error) {
	shellName := "/template_shell_dev_ops" + commonhelper.Rand(10) + ".sh"
	tmpShellPath := step.WorkPath + shellName
	helper.WriteFile(tmpShellPath, step.Shell, 0777)
	command := "cd " + step.WorkPath + " && bash ." + shellName
	if step.Std == nil {
		res, err := tools.GetKernelDriver().ExecShellOrBash(command, false)
		if exist, _ := helper.PathExists(tmpShellPath); exist {
			helper.RemoveAllFile(tmpShellPath)
		}
		return res, err
	} else {
		res, err := tools.GetKernelDriver().ExecShellOrBashWithStdWriter(command, step.Std, step.TimeOutFunc)
		if exist, _ := helper.PathExists(tmpShellPath); exist {
			helper.RemoveAllFile(tmpShellPath)
		}
		return res, err
	}

}

type RemoteRunStep struct {
	Ipaddress   string
	Port        int
	WorkDir     string
	Shell       string
	UserName    string
	Std         *tools.Standard
	TimeOutFunc func() (time int, echoWords string, callBack func())
}

func (step *RemoteRunStep) SetStd(std *tools.Standard) {
	step.Std = std
}

func (step *RemoteRunStep) SetTimeOutHandler(fun func() (time int, echoWords string, callBack func())) {
	step.TimeOutFunc = fun
}

func (step *RemoteRunStep) Run() (*Stream, error) {
	stream := Stream{
		Stderr: &tools.StdWriterWithPid{},
		Stdout: &tools.StdWriterWithPid{},
	}
	if step.Std != nil {
		stream.Stdout = step.Std.Stdout
		stream.Stderr = step.Std.Stderr
	}
	shell := "cd " + step.WorkDir + "\n" + step.Shell + "\n"
	command := tools.SshCommand{
		IpAddress:   step.Ipaddress,
		Port:        step.Port,
		Stdout:      stream.Stdout,
		Stderr:      stream.Stderr,
		UserName:    step.UserName,
		TimeOutFunc: step.TimeOutFunc,
	}
	_, err := command.RunShell(shell)
	if err != nil {
		return &stream, err
	}
	return &stream, nil
}
